package com.xinyue.gateway.server.handler;

import java.io.UnsupportedEncodingException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xinyue.gateway.config.GateServerConfig;
import com.xinyue.gateway.server.MessageID;
import com.xinyue.gateway.server.handler.model.GateUserInfo;
import com.xinyue.gateway.server.message.GateMessageHeader;
import com.xinyue.gateway.server.message.GateMessagePackage;
import com.xinyue.gateway.service.GateChannelGroupService;
import com.xinyue.gateway.utils.ChannelUtil;
import com.xinyue.utils.NettyUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import io.netty.util.concurrent.ScheduledFuture;

/**
 * 这个handler负责和客户端建立连接，并且对连接进行验证。 当服务器收到一个socket连接请求之后，会过一会检测用户是否验证通过，如果验证不通过，则关闭连接，以节省资源。
 * 
 * @author 心悦网络科技有限公司 王广帅
 *
 * @Date 2018年6月14日 下午5:48:17
 */
@Service
@Scope(scopeName = "prototype")
public class ChannelConnectConfirmHandler extends ChannelInboundHandlerAdapter {
    private static Logger logger = LoggerFactory.getLogger(ChannelConnectConfirmHandler.class);
    private static AtomicInteger channelCount = new AtomicInteger();
    private String clientIp;
    private ScheduledFuture<?> waitConnectConfirmFuture = null;
    private GateUserInfo gateUserInfo = null;
    @Autowired
    private GateServerConfig serverConfig;
    @Autowired
    private GateChannelGroupService channelService;


    private boolean isConfirmMessage(int messageId) {
        return messageId == MessageID.ConfirmMessageId;
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        this.clientIp = NettyUtil.getIp(ctx);
        String channelId = ChannelUtil.getChannelId(ctx);
        logger.debug("新建连接,channelId {}，clientIp:{},当前连接数:[{}]", channelId, clientIp, channelCount.incrementAndGet());
        int timeout = serverConfig.getConnectTimeoutSeconds();
        // 添加一个延迟定时器，过一会检测连接是否验证成功
        waitConnectConfirmFuture = ctx.executor().schedule(() -> {
            if (gateUserInfo == null) {
                logger.warn("客户端：{} 连接成功之后没有认证，关闭连接:{}", clientIp, channelId);
                ctx.close();
            }
        }, timeout, TimeUnit.SECONDS);

        ctx.fireChannelActive();

    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        //定义一个唯的key
        AttributeKey<GateUserInfo> attributeKey = AttributeKey.newInstance("GateUserInfo");
        //设置数据
        ctx.channel().attr(attributeKey).set(gateUserInfo);
        //获取数据
        ctx.channel().attr(attributeKey).get();
        logger.debug("连接关闭，clientIp:{}", clientIp);
        if (gateUserInfo != null) {
            channelService.removeChannel(gateUserInfo.getRoleId(), ctx.channel().id());
        }
        channelCount.decrementAndGet();
        ctx.fireChannelInactive();
    }

    private void cancelConfirmSchedule() {
        if (waitConnectConfirmFuture != null) {
            waitConnectConfirmFuture.cancel(false);
        }
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        // 处理连接认证消息
        if (msg instanceof GateMessagePackage) {
            GateMessagePackage gateMessage = (GateMessagePackage) msg;
            GateMessageHeader messageHeader = gateMessage.getHeader();
            int messageId = messageHeader.getMessageId();
            if (this.isConfirmMessage(messageId)) {
                if (gateUserInfo != null) {
                    logger.debug("rid {} channelId {} 重复登陆 ，直接返回", gateUserInfo.getRoleId(), ctx.channel().id().asShortText());
                    // 重复请求，直接返回成功
                    ctx.writeAndFlush(gateMessage);
                    return;
                }
                this.readGateConfirmInfo(gateMessage.getBody());
                if (this.checkToken()) {
                    // 取消定时检测认证
                    this.cancelConfirmSchedule();
                    channelService.closeOldChannelIfExist(ctx.channel().id(), gateUserInfo.getRoleId(), gateMessage);
                    // 记录channel与roleId的对应关系
                    channelService.addChannel(gateUserInfo.getRoleId(), ctx.channel());
                    Attribute<GateUserInfo> gaAttribute = ctx.channel().attr(GateUserInfo.USER_INFO_KEY);
                    gaAttribute.set(gateUserInfo);
                    ctx.writeAndFlush(gateMessage);
                } else {
                    ctx.close();
                    logger.error("token非法，{}", gateUserInfo.toString());
                    return;
                }
            } else {
                ctx.fireChannelRead(gateMessage);
            }

        } else {
            ctx.fireChannelRead(msg);
        }
    }


    private void readGateConfirmInfo(byte[] body) throws UnsupportedEncodingException {
        String bodyToString = new String(body, "utf8");
        JSONObject param = JSON.parseObject(bodyToString);
        gateUserInfo = new GateUserInfo();
        gateUserInfo.setRoleId(param.getLongValue("roleId"));
        gateUserInfo.setUserId(param.getLongValue("userId"));
        gateUserInfo.setToken(param.getString("token"));

    }

    /**
     * 
     * @Desc 检测token是否正确，是否过期
     * @param connectConfirmRequest
     * @return
     * @Author 心悦网络 王广帅
     * @Date 2018年6月14日 下午10:24:49
     *
     */
    private boolean checkToken() {

        return true;
    }

    public GateUserInfo getGateUserInfo() {
        return this.gateUserInfo;
    }
}
